/*
 * SlamTec Base Ref Design
 * Copyright 2009 - 2015 RoboPeak
 * Copyright 2013 - 2015 Shanghai SlamTec Co., Ltd.
 * http://www.slamtec.com
 * All rights reserved.
 */
/*
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "common/common.h"
#include "drv/serial_channel.h"

static infra_channel_desc_t _channel;
static interchip_rx_proc_t _rx_proc;

//串口通道的接收缓存区
static _u8 _serialRxBuffer[CONFIG_DRV_SERIALCHANNEL_RXBUFFERSIZE];
_u8	Uart4_ReceiveTemp[Uart4BuffSize];
_u8 Uart4RevCount=0;
/*
 * 串口中断回调函数
 * 串口接收中断里会调用该函数
 */
static void _serial_on_rx_t(int id, _u32 data)
{
    if (_rx_proc) {
        _u8 data_u8 = data;
        _rx_proc(&_channel, &data_u8, 1);
    }

}
/*
 * 注册上层协议函数
 * 指定了该串口通道下对应的上层协议，如interchip
 */
static void _register_rx_callback(infra_channel_desc_t * handle, interchip_rx_proc_t proc)
{
    _rx_proc = proc;
}
/*
 * 串口通道设置数据到发送缓存区函数
 * 调用更底层的环形发送缓存区来缓存
 */
static _s32 _set_tx_buffer(infra_channel_desc_t * handle, const void *data, size_t size, size_t offset)
{
    return usart_txbuffer_set((USART_TypeDef *) _channel._medialayer_data, data, size, offset);
}
/*
 * 串口通道发送函数
 * 调用等底层的发送函数将环形缓存区的数据全部发送出去
 */
static void _flush_tx(infra_channel_desc_t * handle, size_t size)
{
    usart_txbuffer_flush((USART_TypeDef *) _channel._medialayer_data, size);
}
/*
 * 串口初始化函数
 * 指定了接收缓存区，接收中断的回调函数等
 */

_s32 drv_serialchannel_init(USART_TypeDef * USARTx, _u32 baud, uint16_t stopbit)
{
    if (!usart_begin(USARTx, baud, stopbit))
        return 0;

    _rx_proc = NULL;
    _channel.rxbuffer = _serialRxBuffer;
    _channel._medialayer_data = USARTx;
    _channel.register_rx_callback = &_register_rx_callback;
    _channel.tx_buffer_set = &_set_tx_buffer;
    _channel.tx_flush = &_flush_tx;

    _channel.rxbuffersize = sizeof(_serialRxBuffer);
    _channel.txbuffersize = CONFIG_DRV_SERIALCHANNEL_TXBUFFERSIZE;

    usart_setrecv_func(USARTx, _serial_on_rx_t);

    return 1;
}
/*
 * 串口通道关闭函数
 * 取消绑定的中断接收回调函数和该串口通道对应的uart
 */
void drv_serialchannel_shutdown(USART_TypeDef * USARTx)
{
    usart_setrecv_func(USARTx, NULL);
    usart_shutdown(USARTx);
}
/*
 * 获取当前串口通道函数
 */
infra_channel_desc_t *drv_serialchannel_getchannel()
{
    return &_channel;
}
void uart4_init(u32 bound){
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
 
	// 打开串口GPIO的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	// 打开串口外设的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = bound;
	// 配置 针数据字长
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	// 配置停止位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	// 配置校验位
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	// 配置硬件流控制
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	// 配置工作模式，收发一起
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	// 完成串口的初始化配置
	USART_Init(UART4, &USART_InitStructure);
	
	// 串口中断优先级配置
//	NVIC_Configuration();
 
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);	
	// 使能串口接收中断
	USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);	
	
	// 使能串口
	USART_Cmd(UART4, ENABLE);		

  // 清除发送完成标志
	//USART_ClearFlag(USART1, USART_FLAG_TC);     
}


void uart5_init(u32 bound){
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
 
	// 打开串口GPIO的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD, ENABLE);
	
	// 打开串口外设的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);

	// 将USART Tx的GPIO配置为推挽复用模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	// 配置串口的工作参数
	// 配置波特率
	USART_InitStructure.USART_BaudRate = bound;
	// 配置 针数据字长
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	// 配置停止位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	// 配置校验位
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	// 配置硬件流控制
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	// 配置工作模式，收发一起
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	// 完成串口的初始化配置
	USART_Init(UART5, &USART_InitStructure);
	
	// 串口中断优先级配置
//	NVIC_Configuration();
 
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);	
	// 使能串口接收中断
	USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);	
	
	// 使能串口
	USART_Cmd(UART5, ENABLE);		

  // 清除发送完成标志
	//USART_ClearFlag(USART1, USART_FLAG_TC);     
}


/*****************  发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	USART_SendData(pUSARTx,ch);
		
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}
/*****************************************************************
          从 USART 发送多个字节
*****************************************************************/
void Usart_Write(USART_TypeDef * pUSARTx,  uint8_t	*pu8TxBuf, 	uint32_t u32WriteBytes)
{
    uint32_t  u32Count;
    for (u32Count=0; u32Count<u32WriteBytes; u32Count++)
    {
        pUSARTx->DR=pu8TxBuf[u32Count];
        while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
    }
}
/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}


// 串口中断服务函数
void UART4_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(UART4,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(UART4);
		Uart4_ReceiveTemp[Uart4RevCount]=ucTemp;
		Uart4RevCount++;	
    if(Uart4RevCount>=255)Uart4RevCount=0;
	}	 
}